<?php
/**
 * Flash Messenger (namespaced)
 * This is very similar to the flash messenger that comes with Zend, except that
 * I use namespaces to allow multiple flash types (notice, error, success, etc.)
 *
 * @package		Visi
 * @subpackage	Action Helpers
 * @author		Luke Visinoni <luke.visinoni@gmail.com>
 * @copyright	(c) 2011 Luke Visinoni <luke.visinoni@gmail.com>
 * @version		$Id$
 */
class Visi_Controller_Action_Helper_FlashMessenger extends Zend_Controller_Action_Helper_Abstract implements Countable {

    protected static $_messages = array();
    
    /**
     * These are the messages that get added to the view immediately. See the
     * FlashMessenger plugin to see how it's done.
     */
    protected static $_immediateMessages = array();
    
    protected $_default = 'error';
    
    protected static $_session;
    
    protected static $_messageAdded = false;
    
    /**
     * Constructor
     * For every request, loop through this helper's session namespace, placing
     * its contents into this class's $_messages array. Then clear it from the
     * session.
     */
    public function __construct() {
    
        if (!self::$_session instanceof Zend_Session_Namespace) {
            self::$_session = new Zend_Session_Namespace($this->getName());
        }
    
    }
    
    /**
     * addMessage() - Add a message to flash message in specified namespace
     *
     * @param  string $message
     * @return Zend_Controller_Action_Helper_FlashMessenger Provides a fluent interface
     */
    public function addMessage($message, $namespace = null) {
    
        if (is_null($namespace)) $namespace = $this->_default;
        if (self::$_messageAdded === false) {
            self::$_session->setExpirationHops(1, null, true);
            self::$_messageAdded = true;
        }
        // hack!
        if (!in_array($message, self::$_session->{$namespace})) {
            self::$_session->{$namespace}[] = $message;
        }

    }

    /**
     * hasMessages() - Wether a specific namespace has messages
     *
     * @return boolean
     */
    public function hasMessages($namespace = null) {
    
    	if (is_null($namespace)) $namespace = $this->_default;
        return isset(self::$_session->{$namespace});
    
    }

    /**
     * getMessages() - Get messages from a specific namespace
     *
     * @return array
     */
    public function getMessages($namespace = null) {
    
    	if (is_null($namespace)) $namespace = $this->_default;
        if ($this->hasMessages($namespace)) {
            return self::$_session->{$namespace};
        }
        return array();
    
    }

    /**
     * Clear all messages from the previous request & current namespace
     *
     * @return boolean True if messages were cleared, false if none existed
     */
    public function clearMessages($namespace = null) {
    
    	if (is_null($namespace)) $namespace = $this->_default;
        if ($this->hasMessages($namespace)) {
            unset(self::$_session->{$namespace});
            return true;
        }
        return false;
    
    }
    
    public function getAllMessages() {
    
        $msgArray = array();
        foreach (self::$_session as $namespace => $messages) {
            $msgArray[$namespace] = $messages;
        }
        return $msgArray;
    
    }

    /**
     * clear all messages from all namespaces
     *
     * @return boolean
     */
    public function clearAllMessages() {
    
        self::$_session->unsetAll();
        return true;

    }

    /**
     * count() - Complete the countable interface
     *
     * @return int
     */
    public function count($namespace = null) {
    
    	if (is_null($namespace)) $namespace = $this->_default;
        if ($this->hasMessages($namespace)) {
            return count($this->getMessages($namespace));
        }
        return 0;

    }

    /**
     * Strategy pattern: proxy to addMessage()
     * 
     * @param  string $message 
     * @return void
     */
    public function direct($message, $namespace = null) {
    
    	if (is_null($namespace)) $namespace = $this->_default;
        return $this->addMessage($message, $namespace);
	
    }
    
    /**
     * Returns an array of namespaces so that we can iterate over them
     */
    public function getNameSpaces() {
    
        return array_keys(self::$_messages);
    
    }
    
    /**
     * Sometimes we want to flash a message on the current request rather than
     * the next one. In those cases, we use this method rather than direct().
     * There is a plugin that grabs these messages and adds them to the view.
     */
    public function flash($message, $namespace = null) {
    
        if (is_null($namespace)) {
            $namespace = $this->_default;
        }
        if (!array_key_exists($namespace, self::$_immediateMessages)) {
            self::$_immediateMessages[$namespace] = array();
        }
        self::$_immediateMessages[$namespace][] = $message;
    
    }
    
    public function getImmediateMessages($namespace = null) {
    
        if (is_null($namespace)) {
            return self::$_immediateMessages;
        }
        if (!array_key_exists($namespace, self::$_immediateMessages)) {
            throw new Visi_Controller_Action_Helper_Exception("'{$namespace}' is not a defined flash messenger namespace.");
        }
        return self::$_immediateMessages[$namespace];
    
    }

}
